module cache(
    input clk,
    input reset,
    input hit,
    input hit0,
    input hit1,
    input [63:0] addr,
    input [63:0] wdata,
    input [1:0] control,
    input [63:0] mem_data,
    input write_way,
    input [7:0] write_mask,
    output reg [63:0] data,
    output reg [63:0] write_back_data,
    output reg [7:0] write_back_mask,
    output reg write_back_ena

);

    reg [64:0] data_arrays_0[0:63];
    reg [64:0] data_arrays_1[0:63];

    always @(posedge clk) begin
        if(reset) begin
            genvar i;
	        generate
		        for (i = 0; i < 64; i = i + 1) begin
                    data_arrays_0[i] <= 65'd0;
                    data_arrays_1[i] <= 65'd0; 
		        end
	        endgenerate
        end else if(control == 2'b01) begin //load
            if(hit) begin
                if(hit0) begin
                    data <= data_arrays_0[addr[9:3]][64:1];
                end else begin
                    data <= data_arrays_1[addr[9:3]][64:1];
                end
            end else begin
                data <= mem_data;
                if(write_way) begin
                    if(data_arrays_0[addr[9:3]][0] == 1'b0) begin
                        data_arrays_0[addr[9:3]][64:1] <= mem_data;
                        write_back_ena <= 1'b0;
                        write_back_mask <= 8'b00000000;
                        write_back_data <= 64'd0;
                    end else begin
                        write_back_data = data_arrays_0[addr[9:3]][64:1];
                        write_back_ena <= 1'b1;
                        write_back_mask <= 8'b11111111;
                        data_arrays_0[addr[9:3]][64:1] <= mem_data;
                    end
                    data_arrays_0[addr[9:3]][0] == 1'b0;
                end else begin
                    if(data_arrays_1[addr[9:3]][0] == 1'b0) begin
                        data_arrays_1[addr[9:3]][64:1] <= mem_data;
                        write_back_ena <= 1'b0;
                        write_back_mask <= 8'b00000000;
                        write_back_data <= 64'd0;
                    end else begin
                        write_back_data <= data_arrays_1[addr[9:3]][64:1];
                        write_back_ena <= 1'b1;
                        write_back_mask <= 8'b11111111;
                        data_arrays_1[addr[9:3]][64:1] <= mem_data;
                    end
                    data_arrays_1[addr[9:3]][0] == 1'b0;
                end
            end
        end else if(control == 2'b10) begin
            if(hit) begin
                if(hit0) begin
                    case(write_mask)
                        8'b00000001 : begin
                            data_arrays_0[addr[9:3]][8:1] <= wdata[7:0];
                        end
                        8'b00000010 : begin
                            data_arrays_0[addr[9:3]][16:9] <= wdata[15:8];
                        end
                        8'b00000100 : begin
                            data_arrays_0[addr[9:3]][24:17] <= wdata[23:16];
                        end
                        8'b00001000 : begin
                            data_arrays_0[addr[9:3]][32:25] <= wdata[31:24];
                        end
                        8'b00010000 : begin
                            data_arrays_0[addr[9:3]][40:33] <= wdata[39:32];
                        end
                        8'b00100000 : begin
                            data_arrays_0[addr[9:3]][48:41] <= wdata[47:40];
                        end
                        8'b01000000 : begin
                            data_arrays_0[addr[9:3]][56:49] <= wdata[55:48];
                        end
                        8'b10000000 : begin
                            data_arrays_0[addr[9:3]][64:57] <= wdata[63:56];
                        end
                        8'b00000011 : begin
                            data_arrays_0[addr[9:3]][16:1] <= wdata[15:0];
                        end
                        8'b00001100 : begin
                            data_arrays_0[addr[9:3]][32:17] <= wdata[31:16];
                        end
                        8'b00110000 : begin
                            data_arrays_0[addr[9:3]][48:33] <= wdata[47:32];
                        end
                        8'b11000000 : begin
                            data_arrays_0[addr[9:3]][64:49] <= wdata[63:48];
                        end
                        8'b00001111 : begin
                            data_arrays_0[addr[9:3]][32:1] <= wdata[31:0];
                        end
                        8'b11110000 : begin
                            data_arrays_0[addr[9:3]][64:1] <= wdata[63:32];
                        end
                        8'b11111111 : begin
                            data_arrays_0[addr[9:3]][64:1] <= wdata[63:0];
                        end
                        default : begin
                            
                        end
                    endcase
                    data_arrays_0[addr[9:3]][0] <= 1'b1;
                end else begin
                    case(write_mask)
                        8'b00000001 : begin
                            data_arrays_1[addr[9:3]][8:1] <= wdata[7:0];
                        end
                        8'b00000010 : begin
                            data_arrays_1[addr[9:3]][16:9] <= wdata[15:8];
                        end
                        8'b00000100 : begin
                            data_arrays_1[addr[9:3]][24:17] <= wdata[23:16];
                        end
                        8'b00001000 : begin
                            data_arrays_1[addr[9:3]][32:25] <= wdata[31:24];
                        end
                        8'b00010000 : begin
                            data_arrays_1[addr[9:3]][40:33] <= wdata[39:32];
                        end
                        8'b00100000 : begin
                            data_arrays_1[addr[9:3]][48:41] <= wdata[47:40];
                        end
                        8'b01000000 : begin
                            data_arrays_1[addr[9:3]][56:49] <= wdata[55:48];
                        end
                        8'b10000000 : begin
                            data_arrays_1[addr[9:3]][64:57] <= wdata[63:56];
                        end
                        8'b00000011 : begin
                            data_arrays_1[addr[9:3]][16:1] <= wdata[15:0];
                        end
                        8'b00001100 : begin
                            data_arrays_1[addr[9:3]][32:17] <= wdata[31:16];
                        end
                        8'b00110000 : begin
                            data_arrays_1[addr[9:3]][48:33] <= wdata[47:32];
                        end
                        8'b11000000 : begin
                            data_arrays_1[addr[9:3]][64:49] <= wdata[63:48];
                        end
                        8'b00001111 : begin
                            data_arrays_1[addr[9:3]][32:1] <= wdata[31:0];
                        end
                        8'b11110000 : begin
                            data_arrays_1[addr[9:3]][64:1] <= wdata[63:32];
                        end
                        8'b11111111 : begin
                            data_arrays_1[addr[9:3]][64:1] <= wdata[63:0];
                        end
                        default : begin
                            
                        end
                    endcase
                    data_arrays_1[addr[9:3]][0] <= 1'b1;
                end
            end else begin
                if(write_way) begin
                    if(data_arrays_0[addr[9:3]][0] == 1'b0) begin
                        data_arrays_0[addr[9:3]][64:1] <= mem_data;
                    end else begin
                        write_back_data <= data_arrays_0[addr[9:3]][64:1];
                        write_back_ena <= 1'b1;
                        write_back_mask <= 8'b11111111;
                        data_arrays_0[addr[9:3]][64:1] <= mem_data;
                    end
                    case(write_mask)
                        8'b00000001 : begin
                            data_arrays_0[addr[9:3]][8:1] <= wdata[7:0];
                        end
                        8'b00000010 : begin
                            data_arrays_0[addr[9:3]][16:9] <= wdata[15:8];
                        end
                        8'b00000100 : begin
                            data_arrays_0[addr[9:3]][24:17] <= wdata[23:16];
                        end
                        8'b00001000 : begin
                            data_arrays_0[addr[9:3]][32:25] <= wdata[31:24];
                        end
                        8'b00010000 : begin
                            data_arrays_0[addr[9:3]][40:33] <= wdata[39:32];
                        end
                        8'b00100000 : begin
                            data_arrays_0[addr[9:3]][48:41] <= wdata[47:40];
                        end
                        8'b01000000 : begin
                            data_arrays_0[addr[9:3]][56:49] <= wdata[55:48];
                        end
                        8'b10000000 : begin
                            data_arrays_0[addr[9:3]][64:57] <= wdata[63:56];
                        end
                        8'b00000011 : begin
                            data_arrays_0[addr[9:3]][16:1] <= wdata[15:0];
                        end
                        8'b00001100 : begin
                            data_arrays_0[addr[9:3]][32:17] <= wdata[31:16];
                        end
                        8'b00110000 : begin
                            data_arrays_0[addr[9:3]][48:33] <= wdata[47:32];
                        end
                        8'b11000000 : begin
                            data_arrays_0[addr[9:3]][64:49] <= wdata[63:48];
                        end
                        8'b00001111 : begin
                            data_arrays_0[addr[9:3]][32:1] <= wdata[31:0];
                        end
                        8'b11110000 : begin
                            data_arrays_0[addr[9:3]][64:1] <= wdata[63:32];
                        end
                        8'b11111111 : begin
                            data_arrays_0[addr[9:3]][64:1] <= wdata[63:0];
                        end
                        default : begin
                            
                        end
                    endcase
                end else begin
                    if(data_arrays_1[addr[9:3]][0] == 1'b0) begin
                        data_arrays_1[addr[9:3]][64:1] <= mem_data;
                    end else begin
                        write_back_data <= data_arrays_1[addr[9:3]][64:1];
                        write_back_ena <= 1'b1;
                        write_back_mask <= 8'b11111111;
                        data_arrays_1[addr[9:3]][64:1] <= mem_data;
                    end
                    case(write_mask)
                        8'b00000001 : begin
                            data_arrays_1[addr[9:3]][8:1] <= wdata[7:0];
                        end
                        8'b00000010 : begin
                            data_arrays_1[addr[9:3]][16:9] <= wdata[15:8];
                        end
                        8'b00000100 : begin
                            data_arrays_1[addr[9:3]][24:17] <= wdata[23:16];
                        end
                        8'b00001000 : begin
                            data_arrays_1[addr[9:3]][32:25] <= wdata[31:24];
                        end
                        8'b00010000 : begin
                            data_arrays_1[addr[9:3]][40:33] <= wdata[39:32];
                        end
                        8'b00100000 : begin
                            data_arrays_1[addr[9:3]][48:41] <= wdata[47:40];
                        end
                        8'b01000000 : begin
                            data_arrays_1[addr[9:3]][56:49] <= wdata[55:48];
                        end
                        8'b10000000 : begin
                            data_arrays_1[addr[9:3]][64:57] <= wdata[63:56];
                        end
                        8'b00000011 : begin
                            data_arrays_1[addr[9:3]][16:1] <= wdata[15:0];
                        end
                        8'b00001100 : begin
                            data_arrays_1[addr[9:3]][32:17] <= wdata[31:16];
                        end
                        8'b00110000 : begin
                            data_arrays_1[addr[9:3]][48:33] <= wdata[47:32];
                        end
                        8'b11000000 : begin
                            data_arrays_1[addr[9:3]][64:49] <= wdata[63:48];
                        end
                        8'b00001111 : begin
                            data_arrays_1[addr[9:3]][32:1] <= wdata[31:0];
                        end
                        8'b11110000 : begin
                            data_arrays_1[addr[9:3]][64:1] <= wdata[63:32];
                        end
                        8'b11111111 : begin
                            data_arrays_1[addr[9:3]][64:1] <= wdata[63:0];
                        end
                        default : begin
                            
                        end
                    endcase
                end
            end
        end
    end

endmodule